package eu.webhib.webblog.gui.controller;

import eu.webhib.frmwrk.jsf.base.EditBaseController;
import eu.webhib.frmwrk.jsf.utils.JsfUtil;
import eu.webhib.frmwrk.utils.ApplProperties;
import eu.webhib.webblog.domain.User;
import eu.webhib.webblog.domain.UserRole;
import eu.webhib.webblog.gui.application.GuiApplication;
import eu.webhib.webblog.gui.application.SessionMoveIntf;
import eu.webhib.webblog.service.factory.ServiceFactory;
import eu.webhib.webblog.service.intf.UserService;
import javax.faces.bean.*;
import javax.faces.event.*;
import org.apache.log4j.Logger;

@ManagedBean(name = GuiApplication.authenticationObjectName)
@SessionScoped
public class Authentication extends EditBaseController implements SessionMoveIntf {

   private static final Logger log = Logger.getLogger(Authentication.class);
   private static UserService userService = ServiceFactory.getUserService();
   // User input data
   private String userName;
   private String passWord;
   //
   private Long loggedinUserId = null;
   private UserRole userRole = null;

   //
   public Authentication() {
      log.info("Authentication");
      setInfoMessage("info_login");
   }

   //
   // User input  ----------------------------------------------------------
   //
   public String getUserName() {
      return userName;
   }

   public void setUserName(String userName) {
      this.userName = userName;
   }

   public String getPassWord() {
      return "";
   }

   public void setPassWord(String passWord) {
      this.passWord = passWord;
   }

   public boolean isAuthenticated() {
      return loggedinUserId != null;
   }

   // others may also set a certain user into the logged in state (e.g. password reset)
   // or log out the currently authenticated user forcible
   public void setAuthenticatedUser(User user) {
      if (user == null) {
         // log out user
         this.userName = null;
         this.loggedinUserId = null;
         this.userRole = null;
         setInfoMessage("info_loggedout");
      } else {
         // set to logged in
         this.userName = user.getUserName();
         this.loggedinUserId = user.getId();
         this.userRole = user.getUserRole();
         setInfoMessage("info_loggedin", this.userName);
      }
      // in any case invalidate current session and move data to new one
      GuiApplication.moveToNewSession();
   }

   public Long getAuthenticatedUserId() {
      return loggedinUserId;
   }

   public UserRole getUserRole() {
      return userRole;
   }

   //
   // Login actions and functions -----------------------------------
   //
   public String logInAction() {
      log.info("logInAction");

      return logInActionClosure.start();
   }
   private EditActionClosure logInActionClosure = new EditActionClosure() {

      @Override
      protected void run() {
         loggedinUserId = doLogInAction();
      }
   };

   private Long doLogInAction() {
      if (userName.length() == 0 || passWord.length() == 0) {
         passWord = null;
         setInfoMessage("info_login_empty");
         JsfUtil.sendRedirect(GuiApplication.getLoginPageURI());
         return null;
      }
      User user = userLogIn(userName, passWord);
      if (user == null) {
         passWord = null;
         setErrorMessage("error_login_failed");
         JsfUtil.sendRedirect(GuiApplication.getLoginPageURI());
         return null;
      }
      passWord = null;
      log.info("userName '" + userName + "' logged in");
      // set the data so this user is considerd as logged in
      setAuthenticatedUser(user);

      int loginMaxInactive = ApplProperties.getInt("user.login.maxInactive");
      JsfUtil.getSession().setMaxInactiveInterval(loginMaxInactive);

      log.info("user '" + userName + "' logged in: loginMaxInactive: " + loginMaxInactive);
      JsfUtil.sendRedirect(GuiApplication.getHistroyPageURI());
      return loggedinUserId;
   }

   // Helper
   private User userLogIn(String userName, String passWord) {
      log.debug("userLogIn");
      // lookup user by userName
      User user = userService.findByAttributeSingle("userName", userName);
      if (user == null) {
         log.info("userName '" + userName + "' not found");
         return null;
      }
      // check for passWord and status
      if (!user.userLogIn(passWord)) {
         return null;
      }
      userService.save(user);
      return user;
   }

   //
   // Logout actions and functions -----------------------------------
   //
   /* Wrapper for logOutAction action to be used in GET Request  */
   public void logOutActionListener(ComponentSystemEvent event) {
      logOutAction();
   }

   /* Used by FORM button */
   public String logOutAction() {
      log.info("logOutAction");
      return logOutActionClosure.start();
   }
   /** avoid instantiation of closure object at each time */
   private EditActionClosure logOutActionClosure = new EditActionClosure() {

      @Override
      protected void run() {
         log.info("user '" + userName + "' logged out");
         /** set the data so this user is considered as logged out */
         setAuthenticatedUser(null);

         JsfUtil.sendRedirect(GuiApplication.getHistroyPageURI());
      }
   };
}
